package org.gdufe.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //配置用户信息服务，springsecurity会通过请求这个服务的 loadUserByUsername方法来获取用户信息并比对密码
    /*@Bean
    public UserDetailsService userDetailsService() {
        //这里配置用户信息,这里暂时使用这种方式将用户存储在内存中
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
        manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
        return manager;
    }*/

    @Autowired
    UserDetailsService myUserDetailsService;

    @Autowired
    AuthenticationProvider authenticationProvider;

    @Bean
    public PasswordEncoder passwordEncoder(){
        //密码为明文方式
         return NoOpPasswordEncoder.getInstance();
    }



    /**自定义AuthenticationManager
     *
     * 要插入AuthenticationProvider的新实现，需要在项目的配置类中重写WebSecurityConfigurerAdapter类的configure(AuthenticationManagerBuilder auth)方法。
     *
     * 重写配置中的configure(AuthenticationManagerBuilder builder)方法，就会覆盖工厂默认的AuthenticationManager bean
     *
     * 一旦通过 configure 方法自定义 AuthenticationManager实现 就回将工厂中自动配置AuthenticationManager 进行覆盖
     * 一旦通过 configure 方法自定义 AuthenticationManager实现 需要在实现中指定认证数据源对象 UserDetaiService 实例
     * 一旦通过 configure 方法自定义 AuthenticationManager实现 这种方式创建AuthenticationManager对象工厂内部本地一个 AuthenticationManager 对象 不允许在其他自定义组件中进行注入
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //自定义AuthenticationManager后需要手动配置上面的userDetailsService
        auth.userDetailsService(myUserDetailsService);//改的是DaoAuthenticationProvider
        //通过auth.authenticationProvider()自定authenticationProvider
        auth.authenticationProvider(authenticationProvider);
    }
    //默认的AuthenticationManager，在任何地方都可以注入使用，但是这种自定义方式创建的AuthenticationManager是对象工厂内部本地的一个AuthenticationManager，
    //在其他地方使用自定义的AuthenticationManager，比如我们的controller中注入的时候就会出错，需要我们将自定义的AuthenticationManager暴露出去
    //将上面自定义的AuthenticationManager在工厂中暴露，可以在任何位置注入
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                csrf().disable()//关闭 CSRF 因为前端向后台发送 post 请求时，必须验证 csrf，否则会报错 403 Forbidden。
                .authorizeRequests()
                .antMatchers("/**/r/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin().successForwardUrl("/auth/login-success");
    }

    //web应用的全局配置，常用于静态资源的处理配置
    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }
}
